/**
 * @brief 显示相关功能的实现文件
 * @details 该文件实现了一系列用于控制台界面显示的功能函数，通过调用其他相关库和模块（如 `calendar` 模块、`console_color` 模块等）来完成界面的初始化、重置以及各种信息的显示操作。
 */
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "..\..\include\calendar\calendar.h"
#include "..\..\include\calendar\calendar_table.h"
#include "..\..\include\console\console_color.h"
#include "..\..\include\console\console_font.h"
#include "..\..\include\system\system_time.h"
#include "..\..\include\interface\display.h"

// 保存默认控制台属性，用于后续重置操作
static WORD defaultAttributes = 0;
// 控制台输出句柄
static HANDLE hConsole = NULL;
// 第一次展示动态效果
static bool first_show =true;
/**
 * @brief 初始化控制台，设置控制台的相关属性，如清屏、字体、颜色等。
 * @details 此函数首先调用 `system("cls")` 清屏，然后调用 `SetConsoleFont` 设置控制台字体为默认（黑体，大小24，UTF - 8），最后调用 `SetConsoleColor` 将文本颜色设置为黑色，背景颜色设置为白色。
 */
void InitConsole() {
    system("cls");
    SetConsoleFont(NULL, 24, 65001, TRUE);// 使用默认设置（黑体，大小24，UTF-8）
    SetConsoleColor(BLACK_TEXT, WHITE_BG);
}

/**
 * @brief 重置控制台，恢复控制台的默认颜色和字体设置，并清屏。
 * @details 该函数先调用 `ResetConsoleColor` 重置控制台颜色为初始状态，再调用 `ResetConsoleFont` 重置控制台字体，最后调用 `system("cls")` 清屏。
 */
void TermConsole(){
    ResetConsoleColor();
    ResetConsoleFont();
    system("cls");
}

/**
 * @brief 显示万年历的标题界面，包含万年历名称、支持年份范围等信息。
 * @details 此函数会先调用 `system("cls")` 清屏，然后打印万年历的标题相关信息，包括名称、ASCII艺术字形式的图案以及支持的年份范围，并提示用户程序开始运行后尽快输入信息，否则一定时间后自动退出，最后调用 `system("pause")` 暂停等待用户按键。
 */
void ShowTitle()
{
    system("cls");
    printf("\n\n\n"
           "\t\t\t━━━━━━━━━━━━━━超级万年历━━━━━━━━━━━━━━\n");
    printf(
           "\t\t\t███████╗██╗   ██╗██████╗ ███████╗██████╗ \n"
           "\t\t\t██╔════╝██║   ██║██╔══██╗██╔════╝██╔══██╗\n"
           "\t\t\t███████╗██║   ██║██████╔╝█████╗  ██████╔╝\n"
           "\t\t\t╚════██║██║   ██║██╔═══╝ ██╔══╝  ██╔══██╗\n"
           "\t\t\t███████║╚██████╔╝██║     ███████╗██║  ██║\n"
           "\t\t\t╚══════╝ ╚═════╝ ╚═╝     ╚══════╝╚═╝  ╚═╝\n"
          );
    printf(" \t\t\t━━━━━━━━━━（支持1840～2100年）━━━━━━━━━━\n\n\n");
    printf("\n程序开始运行后，请尽快输入信息，否则一定时间后自动退出。\n");

    system("pause");
}

/**
 * @brief 显示万年历的主菜单界面，包含当前时间显示和功能选项。
 * @details 函数首先调用 `system("cls")` 清屏，然后获取当前时间并分别以不同颜色显示年、月、日、时、分、秒和星期。接着动态显示菜单的顶部边框，通过遍历数组以不同颜色显示各个功能选项，再动态显示菜单的底部边框，最后以红色文本提示用户输入选项（按下0退出），并将颜色恢复为默认。
 */
void ShowMenu() {
    system("cls");

    // 当前时间显示
    LONGTIME lt = GetCurTime();

    SetConsoleColor(GREEN_TEXT,WHITE_BG);
    printf("\t\t  当前时间是: ");//🌞

    SetConsoleColor(CYAN_TEXT,WHITE_BG);
    printf("%d-%02d-%02d ", lt.year, lt.month, lt.day);

    SetConsoleColor(BROWN_TEXT,WHITE_BG);
    printf("%02d:%02d:%02d ", lt.hour, lt.minute, lt.second);

    SetConsoleColor(MAGENTA_TEXT,WHITE_BG);
    printf("%s\n\n", dayOfWeek[lt.dayOfWeek]);

    SetConsoleColor(BLACK_TEXT,WHITE_BG);

    // 动态顶部边框
    SetConsoleColor(BLUE_TEXT,WHITE_BG);
    printf("\t\t╔");
    for (int i = 0; i <19; i++) {
        printf("══");
        if(first_show)Sleep(1);
        //fflush(stdout);
    }
    printf("╗\n");

    // 菜单选项（带图标和颜色）
    //const char* icons[] = {"📅", "🌑", "🗓️", "⏱️", "🕰️", "📏", "🌦️", "🎉"};
    const char* options[] = {
        "1、公历查询农历            ", 
        "2、农历查询公历            ", 
        "3、查询公历月历            ", 
        "4、查询某天距今天的天数    ",
        "5、查询距今天相应天数的日期", 
        "6、查询两个公历日期的天数差", 
        "7、查询二十四节            ", 
        "8、查询公历或者农历节日    "
    };
    const int colors[] = {CYAN_TEXT, GREEN_TEXT, MAGENTA_TEXT, BROWN_TEXT, RED_TEXT, BLUE_TEXT, CYAN_TEXT, GREEN_TEXT};

    SetConsoleColor(BLUE_TEXT,WHITE_BG);
    for (int i = 0; i < 8; i++) {
        printf("\t\t║   ");
        SetConsoleColor(colors[i],WHITE_BG);
        // printf("%s  %s",icons[i], options[i]);
        printf("    %s", options[i]);
        printf("    ║\n");
        if(first_show)Sleep(100); // 动态显示效果
    }

    // 动态底部边框
    printf("\t\t╚");
    for (int i = 0; i <19; i++) {
        printf("══");
        if(first_show)Sleep(1);
        //fflush(stdout);
    }
    printf("╝\n\n");

    // 输入提示
    ColorfulPrintString(RED_TEXT, "\t\t\t请输入选项（按下 0 退出）: ");
    SetConsoleColor(BLACK_TEXT,WHITE_BG);
    first_show=false;
}

/**
 * @brief 显示指定公历日期附近的节气信息。
 * @param gre_date 输入的公历日期结构体，用于确定要查询节气信息的日期。
 * @details 函数根据输入的公历日期，先计算出该月的月首天数和当前年份在数据表中的行号，然后通过遍历节气码表，找到当月的节气信息，再将节气的小数日转换为公历日期，最后显示出当月两个节气的名称、日期和时间。
 */
void ShowNearJieqi(GREDATE gre_date)
{
    int year=gre_date.year;
    int month=gre_date.month;
    int day=gre_date.day;
    int base_days=gre_date.baseDays;

    LONGTIME lt;
    double jq1,jq2;
    int index_jieqi=0;				//节气序号
    int dM0=JDNBaseDay(year,month,1);	//公历月首天数
    int row=year-START_YEAR;			//当前年份所处数据表中的行号,从0开始
    for (index_jieqi=(month-1)*2;index_jieqi<24;index_jieqi++)
    {
        jq1=Jieqi[row*24+index_jieqi];
        jq2=Jieqi[row*24+index_jieqi+1];
        if (GetInteger(jq1)<=base_days && GetInteger(jq2)>base_days)break;
    }
    //printf("%lf %d %lf\n",jq1,base_days,jq2);
    //显示当月节气
    lt=GetDate(jq1);
    printf("\n\t%s：%d-%d-%d %02d:%02d:%02d\t\t",jieqi[(index_jieqi)%24],lt.year,lt.month,lt.day,lt.hour,lt.minute,lt.second);

    //printf("%lf\n",jq1);
    //printf("%lf\n",jq2);
    if(GetInteger(jq2)!=0)
    {
        lt=GetDate(jq2);
        printf("%s：%d-%d-%d %02d:%02d:%02d\n",jieqi[(index_jieqi+1)%24],lt.year,lt.month,lt.day,lt.hour,lt.minute,lt.second);
    }  
}

/**
 * @brief 显示指定年份的二十四节气信息。
 * @param year 年份，用于确定要显示节气信息的年份。
 * @details 该函数先计算出指定年份在数据表中的行号，然后从立春开始遍历节气码表，将每个节气的小数日转换为公历日期，再将公历日期转换为农历日期，最后依次显示节气序号、节气名称、交节日期、交节时间、农历日期和星期等信息。
 */
void ShowSolarTerms(int year)
{
    int row=year-START_YEAR;
    int col=3;//从立春开始算。
    GREDATE gre_date;
    LONGTIME lt;
    LUNARDATE lunar_date;
    printf("\n  节气名称\t交节日期\t交节时间\t  农历\t\t星期\n");
    printf("──────────────────────────────────────────────────────────────────────\n");
    for (;col<27;col++)//因为lie初始为3，则算24个节气后，为26，因此小于27
    {
        lt=GetDate(Jieqi[row*24+col]);
        printf("  %02d. ",col-2);
        printf("%s",jieqi[col%24]);
        printf("  \t%d-%d-%d\t%02d:%02d:%02d  ",lt.year,lt.month,lt.day,lt.hour,lt.minute,lt.second);
        gre_date.year=lt.year;
        gre_date.month=lt.month;
        gre_date.day=lt.day;

        GreToLunar(gre_date,&lunar_date);

        ShowLunarDate(lunar_date,gre_date,false);

        if (col==26)printf("  %s\n",dayOfWeek[lt.dayOfWeek]);
        else printf("  %s\n\n",dayOfWeek[lt.dayOfWeek]);
    }
    printf("──────────────────────────────────────────────────────────────────────\n");
}

/**
 * @brief 显示指定月份的公历节日信息。
 * @param month 月份，用于确定要显示公历节日的月份。
 * @details 函数根据输入的月份，通过 `switch` 语句判断并打印该月的所有公历节日名称，包括元旦、情人节、国际妇女节等常见节日。
 */
void ShowHoliday(int month)
{
	printf("\n\t\t\t\t%d月的节日\n",month);
	switch(month)
	{
		case 1:	
			printf("\n\t\t 1月1日元旦(New Year's Day)\n");
			printf("\t\t 1月最后一个星期日国际麻风节\n\n");
			break;
		case 2:
			printf("\n\t\t 2月2日  世界湿地日(World Wetlands Day)\n");
			printf("\t\t 2月14日 情人节(Valentine's Day)\n\n");
			break;
		case 3:
			printf("\n\t\t 3月3日  全国爱耳日\n");
			printf("\t\t 3月5日  青年志愿者服务日\n");
			printf("\t\t 3月8日  国际妇女节(International Women' Day)\n");
			printf("\t\t 3月9日  保护母亲河日\n");
            printf("\t\t 3月12日 中国植树节(China Arbor Day)\n");
            printf("\t\t 3月14日 白色情人节(White Day)\n");
            printf("\t\t 3月14日 国际警察日(International Policemen' Day)\n");
            printf("\t\t 3月15日 世界消费者权益日(World Consumer Right Day)\n");
			printf("\t\t 3月21日 世界森林日(World Forest Day)\n");
            printf("\t\t 3月21日 世界睡眠日(World Sleep Day)\n");
            printf("\t\t 3月22日 世界水日(World Water Day)\n");
            printf("\t\t 3月23日 世界气象日(World Meteorological Day)\n");
			printf("\t\t 3月24日 世界防治结核病日(World Tuberculosis Day)\n");
            printf("\t\t 3月最后一个完整周的星期一中小学生安全教育日\n\n");
			break;
		case 4:
			printf("\n\t\t 4月1日  愚人节(April Fools' Day)\n");
            printf("\t\t 4月5日  清明节(Tomb-sweeping Day)\n");
            printf("\t\t 4月7日  世界卫生日(World Health Day)\n");
            printf("\t\t 4月22日 世界地球日(World Earth Day)\n");
            printf("\t\t 4月26日 世界知识产权日(World Intellectual PropertyDay)\n\n");
			break;
		case 5:
			printf("\n\t\t 5月1日  国际劳动节(International Labour Day)\n");
            printf("\t\t 5月3日  世界哮喘日(World Asthma Day)\n");
            printf("\t\t 5月4日  中国青年节(Chinese Youth Day)\n");
            printf("\t\t 5月8日  世界红十字日(World Red-Cross Day)\n");
            printf("\t\t 5月12日 国际护士节(International Nurse Day)\n");
            printf("\t\t 5月15日 国际家庭日(International Family Day)\n");
            printf("\t\t 5月17日 世界电信日(World Telecommunications Day)\n");
            printf("\t\t 5月20日 全国学生营养日\n");
            printf("\t\t 5月23日 国际牛奶日(International Milk Day)\n");
            printf("\t\t 5月31日 世界无烟日(World No-Smoking Day)\n");
            printf("\t\t 5月第二个星期日母亲节(Mother's Day)\n");
            printf("\t\t 5月第三个星期日全国助残日\n\n");
			break;
		case 6:
			printf("\n\t\t 6月1日  国际儿童节(International Children's Day)\n");
            printf("\t\t 6月5日  世界环境日(International Environment Day)\n");
            printf("\t\t 6月6日  全国爱眼日\n");
            printf("\t\t 6月17日 世界防治荒漠化和干旱日(World Day to combat desertification)\n");
            printf("\t\t 6月23日 国际奥林匹克日(International Olympic Day)\n");
            printf("\t\t 6月25日 全国土地日\n");
            printf("\t\t 6月26日 国际禁毒日(International Day Against Drug Abuse and Illicit Trafficking)\n");
            printf("\t\t 6月第三个星期日父亲节(Father's Day)\n\n");
			break;
		case 7:
			printf("\n\t\t 7月1日  中国共产党诞生日(Anniversary of the Founding of the Chinese Communist Party)\n");
            printf("\t\t 7月1日  国际建筑日(International Architecture Day)\n");
            printf("\t\t 7月7日  中国人民抗日战争纪念日\n");
            printf("\t\t 7月11日 世界人口日(World Population Day)\n\n");
			break;
		case 8:
			printf("\n\t\t 8月1日  中国人民解放军建军节(Army Day)\n");
            printf("\t\t 8月12日 国际青年节(International Youth Day)\n\n");
			break;
		case 9:
			printf("\n\t\t 9月8日  国际扫盲日(International Anti-illiteracy Day)\n");
            printf("\t\t 9月10日 中国教师节(Teacher's Day)\n");
            printf("\t\t 9月16日 中国脑健康日\n");
            printf("\t\t 9月16日 国际臭氧层保护日(International Day for the Preservation of the Ozone Layer)\n");
            printf("\t\t 9月20日 全国爱牙日\n");
            printf("\t\t 9月21日 世界停火日(World Cease-fire Day)\n");
            printf("\t\t 9月27日 世界旅游日(World Tourism Day)\n");
            printf("\t\t 9月第三个星期二国际和平日(International Peace Day)\n");
            printf("\t\t 9月第三个星期六全国国防教育日\n");
            printf("\t\t 9月第四个星期日国际聋人节(International Day of the Deaf)\n\n");
			break;
		case 10:
			printf("\n\t\t 10月1日  中华人民共和国国庆节(National Day)\n");
            printf("\t\t 10月1日  国际音乐日(International Music Day)\n");
            printf("\t\t 10月1日  国际老年人日(International Day of Older Persons)\n");
            printf("\t\t 10月4日  世界动物日(World Animal Day)\n");
            printf("\t\t 10月5日  世界教师日(World Teachers' Day)（联合国教科文组织确立）\n");
            printf("\t\t 10月8日  全国高血压日\n");
            printf("\t\t 10月9日  世界邮政日(World Post Day)\n");
            printf("\t\t 10月10日 世界精神卫生日(World Mental Health Day)\n");
            printf("\t\t 10月14日 世界标准日(World Standards Day)\n");
            printf("\t\t 10月15日 国际盲人节(International Day of the Blind)\n");
            printf("\t\t 10月15日 世界农村妇女日(World Rural Women's Day)\n");
            printf("\t\t 10月16日 世界粮食日(World Food Day)\n");
            printf("\t\t 10月17日 国际消除贫困日(International Day for the Eradication of Poverty)\n");
            printf("\t\t 10月24日 联合国日(United Nations Day)\n");
            printf("\t\t 10月24日 世界发展新闻日(World Development Information Day)\n");
            printf("\t\t 10月28日 中国男性健康日\n");
            printf("\t\t 10月29日 国际生物多样性日(International Biodiversity Day)\n");
            printf("\t\t 10月31日 万圣节(Halloween)\n");
            printf("\t\t 10月的第一个星期一世界住房日(World Habitat Day)\n");
            printf("\t\t 10月的第二个星斯一加拿大感恩节(Thanksgiving Day)\n");
            printf("\t\t 10月第二个星期三国际减轻自然灾害日(International Day for Natural Disaster Reduction)\n");
            printf("\t\t 10月第二个星期四世界爱眼日(World Sight Day)\n\n");
			break;
		case 11:
			printf("\n\t\t 11月8日  中国记者节\n");
            printf("\t\t 11月9日  消防宣传日\n");
            printf("\t\t 11月14日 世界糖尿病日(World Diabetes Day)\n");
            printf("\t\t 11月17日 国际大学生节\n");
            printf("\t\t 11月25日 国际消除对妇女的暴力日(International Day For the elimination of Violence against Women)\n");
            printf("\t\t 11月最后一个星期四美国感恩节(Thanksgiving Day)\n\n");
			break;
		case 12:
			printf("\n\t\t 12月1日  世界爱滋病日(World AIDS Day)\n");
            printf("\t\t 12月3日  世界残疾人日(World Disabled Day)\n");
            printf("\t\t 12月4日  全国法制宣传日\n");
            printf("\t\t 12月9日  世界足球日(World Football Day)\n");
            printf("\t\t 12月25日 圣诞节(Christmas Day)\n");
			printf("\t\t 12月29日 国际生物多样性日(International Biological Diversity Day)\n\n");
			break;
		}
}

/**
 * @brief 显示农历日期相关信息，可选择是否显示节气信息。
 * @param lunar_date 输入的农历日期结构体，包含农历日期的相关信息。
 * @param gre_date 对应的公历日期结构体，用于辅助计算和显示。
 * @param show_jieqi 布尔值，为 `true` 时显示节气信息，为 `false` 时不显示。
 * @details 函数根据输入的农历日期和公历日期信息，先显示农历日期的年、月、日等信息（包括天干、地支、生肖、是否为闰月、月份大小等），如果 `show_jieqi` 为 `true`，还会判断并显示相关节气信息，如当天是否为节气、距离下一个节气的天数等。
 */
void ShowLunarHoliday()
{
	printf("\n\t\t农历正月初一   春节(the Spring Festival)\n");
	printf("\n\t\t农历正月十五   元宵节(Lantern Festival)\n");
	printf("\n\t\t农历五月初五   端午节(the Dragon-Boat Festival)\n");
	printf("\n\t\t农历七月初七   七夕节(中国情人节）(Double-Seventh Day)\n");
	printf("\n\t\t农历八月十五   中秋节(the Mid-Autumn Festival)\n");
	printf("\n\t\t农历九月初九   重阳节(the Double Ninth Festival)\n");
	printf("\n\t\t农历腊月初八   腊八节(the laba Rice Porridge Festival)\n");
	printf("\n\t\t农历腊月二十四 传统扫房日\n\n");
}

/**
 * @brief 显示公历日期信息
 * @param gre_date 输入的公历日期结构体，包含要显示的公历日期信息。
 * @details 该函数根据输入的公历日期，计算并在控制台显示公历日期的具体信息，包括年、月、日以及对应的星期。
 * @return void
 */
void ShowLunarDate(LUNARDATE lunar_date,GREDATE gre_date,bool show_jieqi)
{
	int year=gre_date.year;
	int month=gre_date.month;
	//int day=gre_date.day;
	int base_days=gre_date.baseDays;

	int Lyear=lunar_date.year;
	int Lmonth=lunar_date.month;
	int Lday=lunar_date.day;
	int Ldays_of_month=lunar_date.daysOfMonth;
	int LisLeapMonth=lunar_date.isLeapMonth;

	int index_jieqi0,index_jieqi1;
	char *leap=LisLeapMonth?"闰":"";
	char *daxiao=Ldays_of_month==30?"大":"小";

	int row=year-START_YEAR;
	
	if (show_jieqi)        //为true时，显示农历节气
	{		
		printf("\t农历  %s%s[%s]年 %s%s（%s）%s\t\n",tiangan[(Lyear-1984+9000)%10],dizhi[(Lyear-1984+9000)%12],shengxiao[(Lyear-1984+9000)%12],leap,mName[Lmonth-1],daxiao,dName[Lday]);
		for (int i=(month-1)*2;i<48;i++)
		{
			index_jieqi0=GetInteger(Jieqi[row*24+i]+0.5);
			index_jieqi1=GetInteger(Jieqi[row*24+i+1]+0.5);
			if (index_jieqi1>base_days&&index_jieqi0<=base_days)
			{
                //printf("%d %d %d\n",index_jieqi0,base_days,index_jieqi1);
				if (index_jieqi0==base_days)
				{
					LONGTIME lt=GetDate(Jieqi[row*24+i]);
					printf("\n\t今日节气：%s 交节时间：%d-%d-%d %02d:%02d:%02d\n",jieqi[i%24],lt.year,lt.month,lt.day,lt.hour,lt.minute,lt.second);
				}
				else
				{
					printf("\n\t距离下一个节气『%s』还有%d天\n",jieqi[(i+1)%24],index_jieqi1-base_days);
				}
				break;
			}
		}
		
	}
	else
	{
		printf("%s%s年 %s%s(%s)%s",tiangan[(Lyear-1984+9000)%10],
		dizhi[(Lyear-1984+9000)%12],leap,mName[Lmonth-1],daxiao,dName[Lday]);
	}
}

/**
 * @brief 显示公历日期信息
 * @param gre_date 输入的公历日期结构体，包含要显示的公历日期信息。
 * @details 该函数根据输入的公历日期，计算并在控制台显示公历日期的具体信息，包括年、月、日以及对应的星期。
 * @return void
 */
void ShowGreDate(GREDATE gre_date)
{
	int year=gre_date.year;
	int month=gre_date.month;
	int day=gre_date.day;
	int day_of_week=ZellerWeek(year,month,day);
	printf("公历日期：");
	printf("%d年%d月%d日 %s\n",year,month,day,dayOfWeek[day_of_week]);
}